﻿/*
 * KLF Headless Browser
 * Written by Kris Oye <kristianoye@gmail.com>
 * Copyright (C) 2011-2012.  All rights reserved.
 */
namespace KLF.Lib.Browser.XMLHTTP
{
    #region Using Statements

    using System;
    using System.Linq;
    using System.Text;
    using System.Net;
    using System.Collections.Generic;

    using KLF.Lib.Browser.DOM.Events;
    using KLF.Lib.Browser.DOM.HTML;
    using KLF.Lib.Browser.Events;

    #endregion

    public class XMLHttpRequest : IXMLHttpRequest
    {
        #region States

        public const int STATE_UNSENT = 0;
        public const int STATE_OPENED = 1;
        public const int STATE_HEADERS_RECEIVED = 2;
        public const int STATE_LOADING = 3;
        public const int STATE_DONE = 4;

        #endregion
        #region Constructors

        internal XMLHttpRequest()
        {
            readyState = STATE_UNSENT;
            _events = new Dictionary<string, List<object>>();
        }

        #endregion

        #region Attributes

        internal Dictionary<string, List<object>> _events { get; set; }

        /// <summary>
        /// The context that this object is currently fulfilling.
        /// </summary>
        internal RequestContext CallingContext { get; set; }

        /// <summary>
        /// The context that spawned this XMLHttpRequest object.
        /// </summary>
        internal RequestContext ExecutingContext { get; set; }

        #endregion

        #region IXMLHttpRequest Members

        public object onreadystatechange
        {
            get { throw new NotImplementedException(); }
        }

        public int readyState
        {
            get
            {
                return _readyState;
            }
            internal set
            {
                if (onreadystatechange != null)
                {
                    Event readyStateChangeEvent = new Event(HTMLConstants.HTML_EVENT_HTMLEVENTS);
                    readyStateChangeEvent.initEvent(HTMLConstants.HTML_EVENT_READY_STATE_CHANGE, false, false);
                    readyStateChangeEvent.target = this;
                    dispatchEvent(readyStateChangeEvent);
                }
                _readyState = value;
            }
        }
        private int _readyState;

        public int timeout
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public IXMLHttpRequestUpload upload
        {
            get { throw new NotImplementedException(); }
        }

        public bool withCredentials
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void open(string method, string url, bool async, string user, string password)
        {
            CallingContext = new RequestContext(null, new Uri(url));

            if (!String.IsNullOrEmpty(user)  || !String.IsNullOrEmpty(password))
                CallingContext.Credentials = new NetworkCredential(user, password);

            try
            {
                CallingContext.BuildRequest();
            }
            catch (Exception ex)
            {
                EventError(ex);
            }
        }

        private void EventError(Exception ex)
        {
            dispatchEvent(new ProgressEvent(
                HTMLConstants.HTML_EVENT_ERROR,
                new
                {
                    bubbles = false,
                    cancelable = false,
                    lengthComputable = false,
                    loaded = 0ul,
                    total = 0ul,
                    target = this
                }));
        }

        public void open(string method, string url, bool async, string user)
        {
            open(method, url, async, user, null);
        }

        public void open(string method, string url, bool async)
        {
            open(method, url, async, null, null);
        }

        public void open(string method, string url)
        {
            open(method, url, true, null, null);
        }

        public void setRequestHeader(string header, string value)
        {
            throw new NotImplementedException();
        }

        public void send()
        {
            throw new NotImplementedException();
        }

        public void send(KLF.Lib.Browser.DOM.TypedArray.IArrayBuffer data)
        {
            throw new NotImplementedException();
        }

        public void send(IBlob data)
        {
            throw new NotImplementedException();
        }

        public void send(KLF.Lib.Browser.DOM.Document data)
        {
            throw new NotImplementedException();
        }

        public void send(string data)
        {
            throw new NotImplementedException();
        }

        public void send(FormData data)
        {
            throw new NotImplementedException();
        }

        public void abort()
        {
            throw new NotImplementedException();
        }

        public int status
        {
            get { throw new NotImplementedException(); }
        }

        public string statusText
        {
            get { throw new NotImplementedException(); }
        }

        public string getResponseHeader(string header)
        {
            throw new NotImplementedException();
        }

        public string getAllResponseHeaders()
        {
            throw new NotImplementedException();
        }

        public void overrideMimeType(string mime)
        {
            throw new NotImplementedException();
        }

        public IXMLHttpRequestResponseType responseType
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public object response
        {
            get { throw new NotImplementedException(); }
        }

        public string responseText
        {
            get { throw new NotImplementedException(); }
        }

        public KLF.Lib.Browser.DOM.Document responseXML
        {
            get { throw new NotImplementedException(); }
        }

        #endregion

        #region IXMLHttpRequestEventTarget Members

        public object onloadstart
        {
            get;
            set;
        }

        public object onprogress
        {
            get;
            set;
        }

        public object onabort
        {
            get;
            set;
        }

        public object onerror
        {
            get;
            set;
        }

        public object onload
        {
            get;
            set;
        }

        public object ontimeout
        {
            get;
            set;
        }

        public object onloadend
        {
            get;
            set;
        }

        #endregion

        #region IEventTarget Members

        public void addEventListener(string type, object listener, bool useCapture)
        {
            type = type.ToLowerInvariant();

            if (_events == null)
                _events = new Dictionary<string, List<object>>();

            if (!_events.ContainsKey(type))
                _events[type] = new List<object>();

            if (_events.ContainsKey(type))
            {
                if (!_events[type].Contains(listener))
                    _events[type].Add(listener);
            }
        }

        public bool dispatchEvent(KLF.Lib.Browser.DOM.Events.IEvent evt)
        {
            if (_events != null)
            {
                if (_events.ContainsKey(evt.type))
                {
                    object[] listeners = _events[evt.type].ToArray();

                    foreach (object oListener in listeners)
                    {
                        if (((Event)evt).stopped)
                            continue;
                        ExecutingContext
                            .ExecuteEvent(evt, oListener, "on" + evt.type);
                    }
                }
            }
            return !(evt as Event).stopped;
        }

        public void removeEventListener(string type, object listener, bool useCapture)
        {
            type = type.ToLowerInvariant();

            if (_events == null)
                return;

            if (!_events.ContainsKey(type))
                return;

            if (!_events[type].Contains(listener))
                return;

            _events[type].Remove(listener);

            //  Cleanup if possible
            if (_events[type].Count == 0)
                _events.Remove(type);

            if (_events.Count == 0)
                _events = null;
        }

        #endregion
    }
}
